﻿using System;
using System.Dynamic;
using System.Linq.Expressions;

namespace XEnamel
{
	/// <summary>
	/// This is the minimum required to invoke a dynamic method.
	/// </summary>
	/// <remarks>
	/// This is by no means as safe as it should be.  It needs to be cleaned up.
	/// </remarks>
	public class SimpleInvokeBinder : InvokeBinder
	{
		public SimpleInvokeBinder(CallInfo callInfo)
			: base(callInfo)
		{
		}

		public override DynamicMetaObject FallbackInvoke(DynamicMetaObject target, DynamicMetaObject[] args, DynamicMetaObject errorSuggestion)
		{
			if (target.LimitType.IsSubclassOf(typeof(Delegate)))
			{
				var parms = target.LimitType.GetMethod("Invoke").GetParameters();
				var callArgs = ExpressionEx.ConvertArguments(args, parms);
				return new DynamicMetaObject(
					ExpressionEx.EnsureObjectResult(
						Expression.Invoke(target.Expression.ChangeType(target.LimitType).Convert(target.LimitType), callArgs)),
					BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType));
			}

			return new DynamicMetaObject(
				Expression.Throw(
					Expression.New(
						typeof(Exception).GetConstructor(new[] { typeof(string) }),
						Expression.Constant("Unable to call the function."))),
				BindingRestrictions.GetTypeRestriction(target.Expression, target.LimitType));
		}
	}
}